//
//  zen_vap_touch.cpp
//  app-ios gl
//
//  Created by MeherTj on 2022/1/22.
//  Copyright © 2022 lover. All rights reserved.
//

#include "zen_vap_touch.h"
#include "zen_vap_activity.h"

namespace Zen { namespace Vap {
	void TouchHandle::remove()
	{
		auto me = dynamic_shared<TouchHandle>();
		if(me != nullptr) {
			Activity::Get()->getTouchDispatcher()->removeTouchHandle(me);
		}
	}

	void TouchHandle::setEnabled(bool v) {
		m_is_enabled = v;
	}
	void TouchHandle::setPriority(int v) {
		if(m_priority == v) return;
		m_priority = v;
		if(m_dispatcher) m_dispatcher->setPriorityDirty();
	}

	void TouchDispatcher::bindTouchHandle(std::shared_ptr<TouchHandle> handle)
	{
		if(handle == nullptr)
		{
			LogE("bind a null TouchHandle");
			return;
		}
		if(handle->getDispatcher()) {
			LogE("handle already bind again?");
			return;
		}
		handle->m_dispatcher = this;
		m_touch_handles.push_back(handle);
		setPriorityDirty();
	}

	void TouchDispatcher::removeTouchHandle(std::shared_ptr<TouchHandle> handle)
	{
		if(handle == nullptr)
		{
			LogE("remove a null TouchHandle");
			return;
		}
		auto iter = m_touch_handles.begin();
		for(; iter != m_touch_handles.end(); ++iter) {
			if(*iter == handle)
			{
				m_touch_handles.erase(iter);
				break;
			}
		}
		handle->m_dispatcher = nullptr;
		if(handle != nullptr && m_current_touch_handle == handle) m_current_touch_handle.reset();
	}

	void TouchDispatcher::removeAllTouchHandles()
	{
		for(auto i : m_touch_handles) {
			i->m_dispatcher = nullptr;
		}
		m_touch_handles.clear();
		m_current_touch_handle.reset();
	}

	void TouchDispatcher::onTouchDown(AppTouch touch)
	{
		if(m_touches.size()) {
			/// extra touch down on multi-touches ---
			auto handle = m_touches[0].attached_handle.lock();
			auto & info = m_touches[touch.no];
			info.attached_handle = handle;
			info.touch = touch;


			if(handle == nullptr || m_current_touch_handle != handle) {
				LogD("rest touch... ignored");
				return;
			}
			// so handle == m_current_handle
			if(!handle->isActived() || !handle->onTouchMove(touch))
			{
				m_current_touch_handle.reset();
			}
		}
		else
		{
			/// main touch down ---
			this->clearPriorityDirty();
			auto handles_copy = m_touch_handles;
			for(auto & i : handles_copy)
			{
				m_current_touch_handle = i;

				if(i->isActived() && i->onTouchDown(touch))
				{
					break;
				}
				m_current_touch_handle.reset();
			}

			auto & info = m_touches[touch.no];
			info.touch = touch;
			info.attached_handle = m_current_touch_handle;
		}
	}
	void TouchDispatcher::onTouchMove(AppTouch touch)
	{

		auto & info = m_touches[touch.no];
		auto handle = info.attached_handle.lock();

		if(handle == nullptr || m_current_touch_handle != handle) {
			LogD("rest touch... ignored, move");
			return;
		}

		if(!handle->isActived() || !handle->onTouchMove(touch))
		{
			m_current_touch_handle.reset();
		}
	}
	void TouchDispatcher::onTouchUp(AppTouch touch)
	{
		auto info = m_touches[touch.no];
		auto handle = info.attached_handle.lock();

		m_touches.erase(touch.no);

		if(handle == nullptr || m_current_touch_handle != handle) {
			LogD("rest touch... ignored, up");
			return;
		}

		if(!handle->isActived() || !handle->onTouchUp(touch))
		{
			m_current_touch_handle.reset();
		}
	}
	void TouchDispatcher::onTouchCancel(AppTouch touch)
	{
		auto info = m_touches[touch.no];
		auto handle = info.attached_handle.lock();

		m_touches.erase(touch.no);

		if(handle == nullptr || m_current_touch_handle != handle) {
			LogD("rest touch... ignored, up");
			return;
		}

		if(!handle->isActived() || !handle->onTouchCancel(touch))
		{
			m_current_touch_handle.reset();
		}
	}

	void TouchDispatcher::setPriorityDirty() {
		m_is_handles_priority_dirty = true;
	}
	void TouchDispatcher::clearPriorityDirty() {
		if(!m_is_handles_priority_dirty) return;
		m_is_handles_priority_dirty = false;

		auto comp = [](std::shared_ptr<TouchHandle> a, std::shared_ptr<TouchHandle> b) {
			return a->m_priority < b->m_priority;
		};
		std::stable_sort(m_touch_handles.begin(), m_touch_handles.end(), comp);
	}
}}
